package com.sikaryofficial.dataindicator.manager;

import cn.hutool.core.util.StrUtil;
import com.anwen.mongo.conditions.query.LambdaQueryChainWrapper;
import com.sikaryofficial.common.core.utils.PageUtil;
import com.sikaryofficial.common.core.web.domain.PageResult;
import com.sikaryofficial.dataindicator.constant.BuriedPointDataConstant;
import com.sikaryofficial.dataindicator.domain.dto.resp.BrowseDataResponse;
import com.sikaryofficial.dataindicator.domain.dto.resp.UserBehaviorDataResponse;
import com.sikaryofficial.dataindicator.domain.entity.BrowseData;
import com.sikaryofficial.dataindicator.domain.entity.UserBehaviorData;
import com.sikaryofficial.dataindicator.domain.dto.req.BrowseDataPageRequest;
import com.sikaryofficial.dataindicator.domain.dto.req.UserBehaviorDataPageRequest;
import com.sikaryofficial.dataindicator.domain.eo.BrowseDataEO;
import com.sikaryofficial.dataindicator.domain.eo.UserBehaviorEO;
import com.sikaryofficial.dataindicator.domain.mapping.BrowseDataMapping;
import com.sikaryofficial.dataindicator.domain.mapping.UserBehaviorMapping;
import com.sikaryofficial.dataindicator.service.IBrowseDataService;
import com.sikaryofficial.dataindicator.service.IUserBehaviorDataService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Optional;

@Component
public class BuriedPointDataManager {

    @Resource
    private IBrowseDataService browseDataService;

    @Resource
    private IUserBehaviorDataService userBehaviorDataService;

    public PageResult<BrowseDataResponse> pageBrowseData(BrowseDataPageRequest req) {
        LambdaQueryChainWrapper<BrowseData> lambdaQuery = browseDataService.lambdaQuery();
        // 搜索查询
        if (BuriedPointDataConstant.SEARCH_TYPE_1.equals(req.getQueryType())) {
            if (StrUtil.isNotBlank(req.getKeyWord())) {
                lambdaQuery
                        .or(q -> q
                                .like(BrowseData::getDate, req.getKeyWord())
                                .like(BrowseData::getType, req.getKeyWord())
                                .like(BrowseData::getPath, req.getKeyWord())
                                .like(BrowseData::getParams, req.getKeyWord())
                                .like(BrowseData::getIp, req.getKeyWord())
                                .like(BrowseData::getIpCountry, req.getKeyWord())
                                .like(BrowseData::getIpProvince, req.getKeyWord())
                                .like(BrowseData::getIpCity, req.getKeyWord())
                                .like(BrowseData::getReferer, req.getKeyWord())
                                .like(BrowseData::getUserAgent, req.getKeyWord())
                                .like(BrowseData::getClient, req.getKeyWord())
                                .like(BrowseData::getUserId, req.getKeyWord())
                                .like(BrowseData::getUserName, req.getKeyWord())
                                .like(BrowseData::getUserEmail, req.getKeyWord())
                        );
            }
        } else {
            lambdaQuery
                    .like(StrUtil.isNotBlank(req.getClient()), BrowseData::getClient, req.getClient())
                    .like(StrUtil.isNotBlank(req.getUserAgent()), BrowseData::getUserAgent, req.getUserAgent())
                    .gte(req.getFromTime() != null, BrowseData::getRpTime, Optional.ofNullable(req.getFromTime()).map(Date::getTime).orElse(null))
                    .lte(req.getToTime() != null, BrowseData::getRpTime, Optional.ofNullable(req.getToTime()).map(Date::getTime).orElse(null))
                    .like(StrUtil.isNotBlank(req.getPath()), BrowseData::getPath, req.getPath())
                    .like(StrUtil.isNotBlank(req.getParams()), BrowseData::getParams, req.getParams())
                    .like(StrUtil.isNotBlank(req.getReferer()), BrowseData::getReferer, req.getReferer())
                    .eq(StrUtil.isNotBlank(req.getType()), BrowseData::getType, req.getType())
                    .and(BuriedPointDataConstant.REGISTERED_USER_YES.equals(req.getRegisteredUser()), q -> q.nin(BrowseData::getUserId, null, "").exists(BrowseData::getUserId, true))
                    .in(BuriedPointDataConstant.REGISTERED_USER_NO.equals(req.getRegisteredUser()), BrowseData::getUserId, null, "")
                    .or(StrUtil.isNotBlank(req.getUserInfo()) || StrUtil.isNotBlank(req.getIpLocation()), q -> q
                            .eq(StrUtil.isNotBlank(req.getUserInfo()), BrowseData::getUserId, req.getUserInfo())
                            .eq(StrUtil.isNotBlank(req.getUserInfo()), BrowseData::getUserName, req.getUserInfo())
                            .eq(StrUtil.isNotBlank(req.getUserInfo()), BrowseData::getUserEmail, req.getUserInfo())
                            .eq(StrUtil.isNotBlank(req.getIpLocation()), BrowseData::getIpCountry, req.getIpLocation())
                            .eq(StrUtil.isNotBlank(req.getIpLocation()), BrowseData::getIpProvince, req.getIpLocation())
                            .eq(StrUtil.isNotBlank(req.getIpLocation()), BrowseData::getIpCity, req.getIpLocation())
                    )
                    ;
        }
        Integer pageNum = req.getPageNum();
        pageNum = pageNum == null ? 1 : pageNum;
        Integer pageSize = req.getPageSize();
        pageSize = pageSize == null ? 10 : pageSize;
        com.anwen.mongo.model.PageResult<BrowseData> page = lambdaQuery
                .orderByDesc(BrowseData::getRpTime)
                .page(pageNum, pageSize);
        return PageUtil.success(BrowseDataMapping.INSTANCE.convertToResponseList(page.getContentData()), page.getTotalSize());
    }

    public PageResult<UserBehaviorDataResponse> pageUserBehaviorData(UserBehaviorDataPageRequest req) {
        LambdaQueryChainWrapper<UserBehaviorData> lambdaQuery = userBehaviorDataService.lambdaQuery();
        // 搜索查询
        if (BuriedPointDataConstant.SEARCH_TYPE_1.equals(req.getQueryType())) {
            if (StrUtil.isNotBlank(req.getKeyWord())) {
                lambdaQuery
                        .or(q -> q
                                .like(UserBehaviorData::getDate, req.getKeyWord())
                                .like(UserBehaviorData::getType, req.getKeyWord())
                                .like(UserBehaviorData::getPath, req.getKeyWord())
                                .regex(UserBehaviorData::getXPath, escapeRegex(req.getKeyWord()))
                                .like(UserBehaviorData::getIp, req.getKeyWord())
                                .like(UserBehaviorData::getIpCountry, req.getKeyWord())
                                .like(UserBehaviorData::getIpProvince, req.getKeyWord())
                                .like(UserBehaviorData::getIpCity, req.getKeyWord())
                                .like(UserBehaviorData::getReferer, req.getKeyWord())
                                .like(UserBehaviorData::getUserAgent, req.getKeyWord())
                                .like(UserBehaviorData::getClient, req.getKeyWord())
                                .like(UserBehaviorData::getUserId, req.getKeyWord())
                                .like(UserBehaviorData::getUserName, req.getKeyWord())
                                .like(UserBehaviorData::getUserEmail, req.getKeyWord())
                        )
                        ;
            }
        } else {
            lambdaQuery
                    .like(StrUtil.isNotBlank(req.getClient()), UserBehaviorData::getClient, req.getClient())
                    .like(StrUtil.isNotBlank(req.getUserAgent()), UserBehaviorData::getUserAgent, req.getUserAgent())
                    .regex(StrUtil.isNotBlank(req.getXPath()), UserBehaviorData::getXPath,  escapeRegex(req.getXPath()))
                    .gte(req.getFromTime() != null, UserBehaviorData::getRpTime, Optional.ofNullable(req.getFromTime()).map(Date::getTime).orElse(null))
                    .lte(req.getToTime() != null, UserBehaviorData::getRpTime, Optional.ofNullable(req.getToTime()).map(Date::getTime).orElse(null))
                    .like(StrUtil.isNotBlank(req.getPath()), UserBehaviorData::getPath, req.getPath())
                    .like(StrUtil.isNotBlank(req.getReferer()), UserBehaviorData::getReferer, req.getReferer())
                    .like(StrUtil.isNotBlank(req.getSource()), UserBehaviorData::getSource, req.getSource())
                    .eq(StrUtil.isNotBlank(req.getType()), UserBehaviorData::getType, req.getType())
                    .and(BuriedPointDataConstant.REGISTERED_USER_YES.equals(req.getRegisteredUser()), q -> q.nin(UserBehaviorData::getUserId, null, "").exists(UserBehaviorData::getUserId, true))
                    .in(BuriedPointDataConstant.REGISTERED_USER_NO.equals(req.getRegisteredUser()), UserBehaviorData::getUserId, null, "")
                    .or(StrUtil.isNotBlank(req.getUserInfo()) || StrUtil.isNotBlank(req.getIpLocation()), q -> q
                            .eq(StrUtil.isNotBlank(req.getUserInfo()), UserBehaviorData::getUserId, req.getUserInfo())
                            .eq(StrUtil.isNotBlank(req.getUserInfo()), UserBehaviorData::getUserName, req.getUserInfo())
                            .eq(StrUtil.isNotBlank(req.getUserInfo()), UserBehaviorData::getUserEmail, req.getUserInfo())
                            .eq(StrUtil.isNotBlank(req.getIpLocation()), UserBehaviorData::getIpCountry, req.getIpLocation())
                            .eq(StrUtil.isNotBlank(req.getIpLocation()), UserBehaviorData::getIpProvince, req.getIpLocation())
                            .eq(StrUtil.isNotBlank(req.getIpLocation()), UserBehaviorData::getIpCity, req.getIpLocation())
                    )
            ;
        }
        Integer pageNum = req.getPageNum();
        pageNum = pageNum == null ? 1 : pageNum;
        Integer pageSize = req.getPageSize();
        pageSize = pageSize == null ? 10 : pageSize;
        com.anwen.mongo.model.PageResult<UserBehaviorData> page = lambdaQuery
                .orderByDesc(UserBehaviorData::getRpTime)
                .page(pageNum, pageSize);
        return PageUtil.success(UserBehaviorMapping.INSTANCE.convertToResponseList(page.getContentData()), page.getTotalSize());
    }

    // 添加一个方法来转义正则表达式中的特殊字符
    private String escapeRegex(String input) {
        if (input == null) {
            return null;
        }
        return input.replaceAll("([\\\\.*+?^${}()\\[\\]|])", "\\\\$1");
    }

    public List<BrowseDataEO> exportBrowseData(BrowseDataPageRequest req) {
        PageResult<BrowseDataResponse> browseDataResponsePageResult = this.pageBrowseData(req);
        return BrowseDataMapping.INSTANCE.convertToEOList(browseDataResponsePageResult.getRows());
    }

    public List<UserBehaviorEO> exportUserBehaviorData(UserBehaviorDataPageRequest req) {
        PageResult<UserBehaviorDataResponse> pageResult = this.pageUserBehaviorData(req);
        return UserBehaviorMapping.INSTANCE.convertToEOList(pageResult.getRows());
    }
}
